/**
 * Copyright(c) ${copyrightYear} ${company}
 * All rights reserved.
 * Created on ${date}
 */
package ${package}.test.dataset.excel;

import java.io.IOException;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.ConvertUtilsBean;
import org.apache.commons.beanutils.converters.DateConverter;
import org.dbunit.dataset.Column;
import org.dbunit.dataset.DataSetException;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.ITable;
import org.dbunit.dataset.excel.XlsDataSet;

/**
 * 从EXCEL数据集文件创建Bean
 * @author ${author}
 */
public class XlsDataSetBeanFactory {

	/**
	 * 从DbUnit的EXCEL数据集文件创建多个bean
	 * 
	 * @param <T>
	 * @param testClass
	 *            被测试的类
	 * @param file
	 *            插入数据的文件
	 * @param tableName
	 *            表名
	 * @param clazz
	 *            Entity类
	 * @return
	 * @throws Exception
	 */
	public static <T> List<T> createBeans(Class testClass, String file,
			String tableName, Class<T> clazz, String[] excludeFields)
			throws Exception {
		BeanUtilsBean beanUtils = createBeanUtils();
		List<Map<String, Object>> propsList = createProps(testClass, file,
				tableName, clazz,excludeFields);
		List<T> beans = new ArrayList<T>();

		for (Map<String, Object> props : propsList) {
			T bean = clazz.newInstance();
			beanUtils.populate(bean, props);
			beans.add(bean);
		}
		return beans;
	}

	/**
	 * 从DbUnit的EXCEL数据集文件创建多个bean
	 * 
	 * @param <T>
	 * @param testClass
	 *            被测试的类
	 * @param file
	 *            插入数据的文件
	 * @param tableName
	 *            表名
	 * @param clazz
	 *            Entity类
	 * @return
	 * @throws Exception
	 */
	public static <T> T createBean(Class testClass, String file,
			String tableName, Class<T> clazz, String[] excludeFields)
			throws Exception {
		BeanUtilsBean beanUtils = createBeanUtils();
		List<Map<String, Object>> propsList = createProps(testClass, file,
				tableName, clazz, excludeFields);
		T bean = clazz.newInstance();
		beanUtils.populate(bean, propsList.get(0));
		return bean;
	}

	/**
	 * 创建属性
	 * 
	 * @param testClass
	 *            被测试的类
	 * @param file
	 *            插入数据的文件
	 * @param tableName
	 *            表名
	 * @return
	 * @throws IOException
	 * @throws DataSetException
	 */
	private static List<Map<String, Object>> createProps(Class testClass,
			String file, String tableName, Class<?> clazz,
			String[] excludeFields) throws IOException, DataSetException {
		List<Map<String, Object>> propsList = new ArrayList<Map<String, Object>>();
		IDataSet expected = new XlsDataSet(testClass.getResourceAsStream(file));
		ITable table = expected.getTable(tableName);
		Column[] columns = table.getTableMetaData().getColumns();
		String columnName = null;
		Object value = null;
		HashMap<String, String> fieldMap = getFieldNameMapping(clazz);
		HashSet<String> excludeFieldSet = new HashSet<String>();
		if (excludeFields != null) {
			excludeFieldSet.addAll(Arrays.asList(excludeFields));
		}
		for (int i = 0; i < table.getRowCount(); i++) {
			Map<String, Object> props = new HashMap<String, Object>();
			for (Column c : columns) {
				columnName = c.getColumnName();
				if (fieldMap.containsKey(columnName)
						&& !excludeFieldSet.contains(columnName)) {
					value = table.getValue(i, columnName);
					props.put(fieldMap.get(columnName), value);
				}
			}
			propsList.add(props);
		}
		return propsList;
	}

	/**
	 * 获取字段映射关系
	 * 
	 * @param clazz
	 *            Entity类
	 * @return
	 */
	private static HashMap<String, String> getFieldNameMapping(Class<?> clazz) {
		HashMap<String, String> result = new HashMap<String, String>();
		for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
			for (Field field : clazz.getDeclaredFields()) {
				if (field.isAnnotationPresent(javax.persistence.Column.class)) {
					javax.persistence.Column columnAnnotation = field
							.getAnnotation(javax.persistence.Column.class);
					result.put(columnAnnotation.name(), field.getName());
				}
			}
		}
		return result;
	}

	/**
	 * 生成Beanutils
	 * 
	 * @return
	 */
	private static BeanUtilsBean createBeanUtils() {
		ConvertUtilsBean convertUtilsBean = createConverUtils();
		return new BeanUtilsBean(convertUtilsBean);
	}

	/**
	 * 创建转换器工具
	 * 
	 * @return
	 */
	private static ConvertUtilsBean createConverUtils() {
		DateConverter dateConverter = new DateConverter();
		dateConverter.setPattern("yyyy-MM-dd");
		ConvertUtilsBean convertUtilsBean = new ConvertUtilsBean();
		convertUtilsBean.register(dateConverter, java.util.Date.class);
		convertUtilsBean.register(dateConverter, Timestamp.class);
		convertUtilsBean.register(dateConverter, java.sql.Date.class);
		return convertUtilsBean;
	}
}